package com.sheliduan.itlearning.common.exception;

import com.sheliduan.itlearning.common.enums.ErrorCodeEnum;
import com.sheliduan.itlearning.common.utils.ResponseData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

/**
 * @author: 断舍离
 * @date: 2025/1/21 10:15
 * @description: 全局异常处理类
 * 一般@ControllerAdvice和@ExceptionHandler配合使用,
 * 应用于所有控制器上, 根据异常类型选择相应方法处理
 **/
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /*
    * 只捕获BizException类型的异常
    * */
    @ExceptionHandler({BizException.class})
    @ResponseBody
    public ResponseData<Object> handleBizException(HttpServletRequest request, BizException e) {
        log.warn("{} request fail, errorCode: {}, errorMessage: {}", request.getRequestURI(), e.getErrorCode(), e.getErrorMessage());
        return ResponseData.fail(e);
    }

    /*
    * 只捕获MethodArgumentNotValidException类型的异常
    * 这个异常是在参数校验出错时抛出的
    * */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseBody
    public ResponseData<Object> handleMethodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException e) {
        // 获取参数错误错误状态码
        String errorCode = ErrorCodeEnum.PARAM_NOT_VALID.getErrorCode();

        // 获取 BindingResult
        BindingResult bindingResult = e.getBindingResult();

        StringBuilder sb = new StringBuilder();

        // 获取校验不通过的字段，并组合错误信息，格式为： 字段信息 提示信息, 当前值: 'xxx';
        Optional.ofNullable(bindingResult.getFieldErrors()).ifPresent(errors -> {
            errors.forEach(error ->
                    sb.append(error.getField())
                            .append(" ")
                            .append(error.getDefaultMessage())
                            .append(", 当前值: '")
                            .append(error.getRejectedValue())
                            .append("'; ")

            );
        });

        // 错误信息
        String errorMessage = sb.toString();

        log.warn("{} request error, errorCode: {}, errorMessage: {}", request.getRequestURI(), errorCode, errorMessage);
        return ResponseData.fail(errorCode, errorMessage);
    }

    /*
     * 捕获其他类型的异常
     * */
    @ExceptionHandler({ Exception.class })
    @ResponseBody
    public ResponseData<Object> handleOtherException(HttpServletRequest request, Exception e) {
        log.error("{} request error, ", request.getRequestURI(), e);
        return ResponseData.fail(ErrorCodeEnum.SYSTEM_ERROR);
    }
}
